//
// Created by twetec on 25-8-16.
//

#include "../include/network_prober/probe_detect/handle_sqlserver_probe_detect.h"

#include <boost/json.hpp>
#include <future>
#include <sybdb.h>

#include <network_prober/utils/constants.h>

using namespace std::literals::chrono_literals;

namespace network_prober::probe_detect
{
/**
 * 数据库错误处理
 */
static int s_dbErrHandler(DBPROCESS* dbproc, int severity, int dberr, int oserr, char* dberrstr, char* oserrstr)
{
    return INT_CANCEL; // 改为返回1允许继续执行
}

/**
 * 数据库消息处理
 */
static int s_dbMsgHandler(DBPROCESS * dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *proc, int line)
{
    return INT_CANCEL; // 改为返回1允许继续执行
}

void tag_invoke(boost::json::value_from_tag, boost::json::value &jv, SQLServerProbeDetectResultIPv4 const &c)
{
    auto& ja = jv.emplace_object();

    ja["interface"] = c.interface;
    ja["target"] = c.target;
    ja["port"] = c.port;
    ja["delay"] = c.delay;
}

HandleSQLServerProbeDetectIPv4::HandleSQLServerProbeDetectIPv4(
    std::string_view interface,
    std::string_view target,
    std::uint32_t port,
    std::string_view userName,
    std::string_view password,
    std::string_view databaseName,
    std::string_view queryStatement
)
    : m_interface(interface), m_target(target), m_port(port), m_userName(userName),
    m_password(password), m_databaseName(databaseName), m_queryStatement(queryStatement)
{
    // 初始化libmongoc库，在应用程序启动时，只调用一次
    std::call_once(utils::g_sqlServerClientInitOnceFlag, [] {
        // 初始化正常
        dbinit();
    });
}

void HandleSQLServerProbeDetectIPv4::detect()
{
    // 建立连接时，开始计时
    m_detectStartTime = std::chrono::steady_clock::now();

    // 指向当前对象的shared_ptr
    auto self{shared_from_this()};

    // 发起探测
    m_onDetectedCallbackFuture = std::async(std::launch::async, [this, self] {
        // 探测结果
        SQLServerProbeDetectResultIPv4 result;
        result.interface = m_interface;
        result.target = m_target;
        result.port = m_port;

        // 初始化db库
        // if (dbinit() == FAIL) {
        //     // 错误信息
        //     SPDLOG_INFO("SQLServer驱动初始化失败..");
        //     // 连接失败，延迟为-1
        //     result.delay = -1;
        //     // 回调结果
        //     m_onDetectedCallback(std::move(result));
        //     // 结束执行
        //     return;
        // }

        // 设置错误执行方式，避免程序退出
        dberrhandle(s_dbErrHandler);
        // 消息处理，避免程序退出
        dbmsghandle(s_dbMsgHandler);

        // 创建登录对象
        LOGINREC* login = dblogin();
        if (login == nullptr) {
            // 错误信息
            SPDLOG_INFO("SQLServer的login对象初始化失败..");
            // 回收资源
            dbloginfree(login);
            // 连接失败，延迟为-1
            result.delay = -1;
            // 回调结果
            m_onDetectedCallback(std::move(result));
            // 结束执行
            return;
        }

        // 设定连接账号
        DBSETLUSER(login, m_userName.c_str());
        // 设定连接密码
        DBSETLPWD(login, m_password.c_str());

        // 设置登录超时时间(秒)
        dbsetlogintime(5);
        // 设置查询超时时间
        dbsettime(5);

        // 连接数据库服务器
        DBPROCESS* dbproc = dbopen(login, (m_target + ":" + std::to_string(m_port)).c_str());
        if (dbproc == nullptr) {
            // 错误信息
            SPDLOG_INFO("SQLServer观测目标连接失败..");
            // 回收资源
            dbclose(dbproc);
            dbloginfree(login);
            // 连接失败，延迟为-1
            result.delay = -1;
            // 回调结果
            m_onDetectedCallback(std::move(result));
            // 结束执行
            return;
        }

        // 切换到指定数据库
        if (dbuse(dbproc, m_databaseName.c_str()) == FAIL) {
            // 错误信息
            SPDLOG_INFO("SQLServer观测目标数据库切换失败..");
            // 回收资源
            dbclose(dbproc);
            dbloginfree(login);
            // 连接失败，延迟为-1
            result.delay = -1;
            // 回调结果
            m_onDetectedCallback(std::move(result));
            // 结束执行
            return;
        }

        // 构建SQL语句
        const char* sql = m_queryStatement.empty()? "SELECT 1" : m_queryStatement.c_str();

        // 提交sql命令
        if (dbcmd(dbproc, sql) == FAIL) {
            // 错误信息
            SPDLOG_INFO("SQLServer观测目标sql命令提交失败..");
            // 回收资源
            dbclose(dbproc);
            dbloginfree(login);
            // 连接失败，延迟为-1
            result.delay = -1;
            // 回调结果
            m_onDetectedCallback(std::move(result));
            // 结束执行
            return;
        }

        // 执行sql命令
        if (dbsqlexec(dbproc) == FAIL) {
            // 错误信息
            SPDLOG_INFO("SQLServer观测目标sql命令执行失败..");
            // 回收资源
            dbclose(dbproc);
            dbloginfree(login);
            // 连接失败，延迟为-1
            result.delay = -1;
            // 回调结果
            m_onDetectedCallback(std::move(result));
            // 结束执行
            return;
        }

        // 回收资源
        dbclose(dbproc);
        dbloginfree(login);

        // SQL正常执行完毕,计算延迟
        result.delay = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now() - m_detectStartTime).count();
        // 回调结果
        m_onDetectedCallback(std::move(result));
    });
}

void HandleSQLServerProbeDetectIPv4::setOnDetectedCallback(std::function<void(SQLServerProbeDetectResultIPv4&&)> callback)
{
    m_onDetectedCallback = std::move(callback);
}

HandleSQLServerProbeDetectIPv4::~HandleSQLServerProbeDetectIPv4()
{

}

void tag_invoke(boost::json::value_from_tag, boost::json::value &jv, SQLServerProbeDetectResultIPv6 const &c)
{
    auto& ja = jv.emplace_object();

    ja["interface"] = c.interface;
    ja["target"] = c.target;
    ja["port"] = c.port;
    ja["delay"] = c.delay;
}

HandleSQLServerProbeDetectIPv6::HandleSQLServerProbeDetectIPv6(
    std::string_view interface,
    std::string_view target,
    std::uint32_t port,
    std::string_view userName,
    std::string_view password,
    std::string_view databaseName,
    std::string_view queryStatement
)
    : m_interface(interface), m_target(target), m_port(port), m_userName(userName),
    m_password(password), m_databaseName(databaseName), m_queryStatement(queryStatement)
{
    // 初始化libmongoc库，在应用程序启动时，只调用一次
    std::call_once(utils::g_sqlServerClientInitOnceFlag, [] {
        // 初始化正常
        dbinit();
    });
}

void HandleSQLServerProbeDetectIPv6::detect()
{
    // 建立连接时，开始计时
    m_detectStartTime = std::chrono::steady_clock::now();

    // 指向当前对象的shared_ptr
    auto self{shared_from_this()};

    // 发起探测
    m_onDetectedCallbackFuture = std::async(std::launch::async, [this, self] {
       // 探测结果
        SQLServerProbeDetectResultIPv6 result;
        result.interface = m_interface;
        result.target = m_target;
        result.port = m_port;

        // 初始化db库
        // if (dbinit() == FAIL) {
        //     // 错误信息
        //     SPDLOG_INFO("SQLServer驱动初始化失败..");
        //     // 连接失败，延迟为-1
        //     result.delay = -1;
        //     // 回调结果
        //     m_onDetectedCallback(std::move(result));
        //     // 结束执行
        //     return;
        // }

        // 设置错误执行方式，避免程序退出
        dberrhandle(s_dbErrHandler);
        // 消息处理，避免程序退出
        dbmsghandle(s_dbMsgHandler);

        // 创建登录对象
        LOGINREC* login = dblogin();
        if (login == nullptr) {
            // 错误信息
            SPDLOG_INFO("SQLServer的login对象初始化失败..");
            // 回收资源
            dbloginfree(login);
            // 连接失败，延迟为-1
            result.delay = -1;
            // 回调结果
            m_onDetectedCallback(std::move(result));
            // 结束执行
            return;
        }

        // 设定连接账号
        DBSETLUSER(login, m_userName.c_str());
        // 设定连接密码
        DBSETLPWD(login, m_password.c_str());

        // 设置登录超时时间(秒)
        dbsetlogintime(5);
        // 设置查询超时时间
        dbsettime(5);

        // 连接数据库服务器
        DBPROCESS* dbproc = dbopen(login, (m_target + ":" + std::to_string(m_port)).c_str());
        if (dbproc == nullptr) {
            // 错误信息
            SPDLOG_INFO("SQLServer观测目标连接失败..");
            // 回收资源
            dbclose(dbproc);
            dbloginfree(login);
            // 连接失败，延迟为-1
            result.delay = -1;
            // 回调结果
            m_onDetectedCallback(std::move(result));
            // 结束执行
            return;
        }

        // 切换到指定数据库
        if (dbuse(dbproc, m_databaseName.c_str()) == FAIL) {
            // 错误信息
            SPDLOG_INFO("SQLServer观测目标数据库切换失败..");
            // 回收资源
            dbclose(dbproc);
            dbloginfree(login);
            // 连接失败，延迟为-1
            result.delay = -1;
            // 回调结果
            m_onDetectedCallback(std::move(result));
            // 结束执行
            return;
        }

        // 构建SQL语句
        const char* sql = m_queryStatement.empty()? "SELECT 1" : m_queryStatement.c_str();

        // 提交sql命令
        if (dbcmd(dbproc, sql) == FAIL) {
            // 错误信息
            SPDLOG_INFO("SQLServer观测目标sql命令提交失败..");
            // 回收资源
            dbclose(dbproc);
            dbloginfree(login);
            // 连接失败，延迟为-1
            result.delay = -1;
            // 回调结果
            m_onDetectedCallback(std::move(result));
            // 结束执行
            return;
        }

        // 执行sql命令
        if (dbsqlexec(dbproc) == FAIL) {
            // 错误信息
            SPDLOG_INFO("SQLServer观测目标sql命令执行失败..");
            // 回收资源
            dbclose(dbproc);
            dbloginfree(login);
            // 连接失败，延迟为-1
            result.delay = -1;
            // 回调结果
            m_onDetectedCallback(std::move(result));
            // 结束执行
            return;
        }

        // 回收资源
        dbclose(dbproc);
        dbloginfree(login);

        // SQL正常执行完毕,计算延迟
        result.delay = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now() - m_detectStartTime).count();
        // 回调结果
        m_onDetectedCallback(std::move(result));
    });
}

void HandleSQLServerProbeDetectIPv6::setOnDetectedCallback(std::function<void(SQLServerProbeDetectResultIPv6&&)> callback)
{
    m_onDetectedCallback = std::move(callback);
}

HandleSQLServerProbeDetectIPv6::~HandleSQLServerProbeDetectIPv6()
{

}

}